package com.openbravo.pos.sales;

import com.openbravo.basic.BasicException;
import com.openbravo.data.gui.JMessageDialog;
import com.openbravo.data.gui.MessageInf;
import com.openbravo.data.loader.LocalRes;
import com.openbravo.pos.customers.DataLogicCustomers;
import com.openbravo.pos.forms.AppLocal;
import com.openbravo.pos.forms.AppProperties;
import com.openbravo.pos.forms.AppView;
import com.openbravo.pos.forms.DataLogicSystem;
import com.openbravo.pos.panels.JTicketsFinder;
import com.openbravo.pos.payment.MPSWebRequest;
import com.openbravo.pos.payment.PaymentInfo;
import com.openbravo.pos.payment.PaymentInfoTicket;
import com.openbravo.pos.printer.DeviceTicket;
import com.openbravo.pos.printer.TicketParser;
import com.openbravo.pos.printer.TicketPrinterException;
import com.openbravo.pos.scripting.ScriptEngine;
import com.openbravo.pos.scripting.ScriptException;
import com.openbravo.pos.scripting.ScriptFactory;
import com.openbravo.pos.ticket.FindTicketsInfo;
import com.openbravo.pos.ticket.TicketInfo;
import com.openbravo.pos.ticket.TicketLineInfo;
import com.openbravo.pos.util.AltEncrypter;
import java.awt.BorderLayout;
import java.io.*;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.xml.rpc.ServiceException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;

public class JTicketsBagTicket extends JTicketsBag {

    private DataLogicSystem m_dlSystem = null;
    protected DataLogicCustomers dlCustomers = null;
    private DeviceTicket m_TP;
    private TicketParser m_TTP;
    private TicketParser m_TTP2;
    private TicketInfo m_ticket;
    private TicketInfo m_ticketCopy;
    private JTicketsBagTicketBag m_TicketsBagTicketBag;
    private JPanelTicketEdits m_panelticketedit;
    private PaymentInfoTicket m_paymentInfoTicket;
    private AppView appConfig;

    /**
     * Creates new form JTicketsBagTicket
     */
    public JTicketsBagTicket(AppView app, JPanelTicketEdits panelticket) {

        super(app, panelticket);
        appConfig = app;
        m_panelticketedit = panelticket;
        m_dlSystem = (DataLogicSystem) m_App.getBean("com.openbravo.pos.forms.DataLogicSystem");
        dlCustomers = (DataLogicCustomers) m_App.getBean("com.openbravo.pos.customers.DataLogicCustomers");

        // Inicializo la impresora...
        m_TP = new DeviceTicket();

        // Inicializo el parser de documentos de ticket
        m_TTP = new TicketParser(m_TP, m_dlSystem); // para visualizar el ticket
        m_TTP2 = new TicketParser(m_App.getDeviceTicket(), m_dlSystem); // para imprimir el ticket

        initComponents();

        m_TicketsBagTicketBag = new JTicketsBagTicketBag(this);

        m_jTicketEditor.addEditorKeys(m_jKeys);
        jTipEditor.addEditorKeys(jeditorTip);
        AppProperties props = appConfig.getProperties();

        boolean isTip = Boolean.parseBoolean(props.getProperty("machine.showTip"));

        jPanel1.setVisible(isTip);


        // Este deviceticket solo tiene una impresora, la de pantalla
        m_jPanelTicket.add(m_TP.getDevicePrinter("1").getPrinterComponent(), BorderLayout.CENTER);
    }

    public void activate() {

        // precondicion es que no tenemos ticket activado ni ticket en el panel

        m_ticket = null;
        m_ticketCopy = null;

        printTicket();


        m_panelticketedit.setActiveTicket(null, null);

        jrbSales.setSelected(true);

        m_jEdit.setVisible(m_App.getAppUserView().getUser().hasPermission("sales.EditTicket"));
        m_jRefund.setVisible(m_App.getAppUserView().getUser().hasPermission("sales.RefundTicket"));
        m_jPrint.setVisible(m_App.getAppUserView().getUser().hasPermission("sales.PrintTicket"));

        // postcondicion es que tenemos ticket activado aqui y ticket en el panel
    }

    public boolean deactivate() {

        // precondicion es que tenemos ticket activado aqui y ticket en el panel        
        m_ticket = null;
        m_ticketCopy = null;
        return true;
        // postcondicion es que no tenemos ticket activado ni ticket en el panel
    }

    public void deleteTicket() {

        if (m_ticketCopy != null) {
            // Para editar borramos el ticket anterior
            try {
                m_dlSales.deleteTicket(m_ticketCopy, m_App.getInventoryLocation());
            } catch (BasicException eData) {
                MessageInf msg = new MessageInf(MessageInf.SGN_NOTICE, AppLocal.getIntString("message.nosaveticket"), eData);
                msg.show(this);
            }
        }

        m_ticket = null;
        m_ticketCopy = null;
        resetToTicket();
    }

    public void canceleditionTicket() {

        m_ticketCopy = null;
        resetToTicket();
    }

    private void resetToTicket() {
        printTicket();
        jTipEditor.reset();
        jTipEditor.activate();
        m_jTicketEditor.reset();
        m_jTicketEditor.activate();
        m_panelticketedit.setActiveTicket(null, null);

    }

    protected JComponent getBagComponent() {
        return m_TicketsBagTicketBag;
    }

    protected JComponent getNullComponent() {
        return this;

    }

    private void readTicket(int iTicketid, int iTickettype) {

        try {
            TicketInfo ticket = (iTicketid == -1)
                    ? m_dlSales.loadTicket(iTickettype, m_jTicketEditor.getValueInteger())
                    : m_dlSales.loadTicket(iTickettype, iTicketid);

            if (ticket == null) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.notexiststicket"));
                msg.show(this);
            } else {
                m_ticket = ticket;

                m_ticketCopy = null; // se asigna al pulsar el boton de editar o devolver
                printTicket();
            }

        } catch (BasicException e) {
            MessageInf msg = new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.cannotloadticket"), e);
            msg.show(this);
        }
        jTipEditor.reset();
        jTipEditor.activate();
        m_jTicketEditor.reset();
        m_jTicketEditor.activate();

    }

    private void printTicket() {

        // imprimo m_ticket

        try {
            m_jEdit.setEnabled(
                    m_ticket != null
                    && (m_ticket.getTicketType() == TicketInfo.RECEIPT_NORMAL || m_ticket.getTicketType() == TicketInfo.RECEIPT_REFUND)
                    && m_dlSales.isCashActive(m_ticket.getActiveCash()));
        } catch (BasicException e) {
            m_jEdit.setEnabled(false);
        }
        m_jRefund.setEnabled(m_ticket != null && m_ticket.getTicketType() == TicketInfo.RECEIPT_NORMAL);
        m_jPrint.setEnabled(m_ticket != null);

        // Este deviceticket solo tiene una impresora, la de pantalla
        m_TP.getDevicePrinter("1").reset();

        if (m_ticket == null) {
            m_jTicketId.setText(null);
        } else {
            m_jTicketId.setText(m_ticket.getName());

            try {
                ScriptEngine script = ScriptFactory.getScriptEngine(ScriptFactory.VELOCITY);
                script.put("ticket", m_ticket);
                m_TTP.printTicket(script.eval(m_dlSystem.getResourceAsXML("Printer.TicketPreview")).toString());
            } catch (ScriptException e) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.cannotprintticket"), e);
                msg.show(this);
            } catch (TicketPrinterException eTP) {
                MessageInf msg = new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.cannotprintticket"), eTP);
                msg.show(this);
            }
        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        buttonGroup1 = new javax.swing.ButtonGroup();
        m_jOptions = new javax.swing.JPanel();
        m_jButtons = new javax.swing.JPanel();
        m_jTicketId = new javax.swing.JLabel();
        jButton2 = new javax.swing.JButton();
        m_jEdit = new javax.swing.JButton();
        m_jRefund = new javax.swing.JButton();
        m_jPrint = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        m_jPanelTicket = new javax.swing.JPanel();
        jPanel3 = new javax.swing.JPanel();
        jPanel4 = new javax.swing.JPanel();
        m_jKeys = new com.openbravo.editor.JEditorKeys();
        jPanel5 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        m_jTicketEditor = new com.openbravo.editor.JEditorIntegerPositive();
        jPanel1 = new javax.swing.JPanel();
        jrbSales = new javax.swing.JRadioButton();
        jrbRefunds = new javax.swing.JRadioButton();
        jLabel1 = new javax.swing.JLabel();
        jButton3 = new javax.swing.JButton();
        jTipEditor = new com.openbravo.editor.JEditorDoublePositive();
        jeditorTip = new com.openbravo.editor.JEditorKeys();

        setLayout(new java.awt.BorderLayout());

        m_jButtons.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        m_jTicketId.setBackground(java.awt.Color.white);
        m_jTicketId.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        m_jTicketId.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Button.darkShadow")), javax.swing.BorderFactory.createEmptyBorder(1, 4, 1, 4)));
        m_jTicketId.setOpaque(true);
        m_jTicketId.setPreferredSize(new java.awt.Dimension(160, 25));
        m_jTicketId.setRequestFocusEnabled(false);
        m_jButtons.add(m_jTicketId);

        jButton2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/openbravo/images/search24.png"))); // NOI18N
        jButton2.setText(AppLocal.getIntString("label.search")); // NOI18N
        jButton2.setToolTipText("Search Tickets");
        jButton2.setFocusPainted(false);
        jButton2.setFocusable(false);
        jButton2.setMargin(new java.awt.Insets(8, 14, 8, 14));
        jButton2.setMaximumSize(new java.awt.Dimension(100, 44));
        jButton2.setMinimumSize(new java.awt.Dimension(82, 44));
        jButton2.setPreferredSize(new java.awt.Dimension(100, 44));
        jButton2.setRequestFocusEnabled(false);
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        m_jButtons.add(jButton2);

        m_jEdit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/openbravo/images/sale_editline.png"))); // NOI18N
        m_jEdit.setText(AppLocal.getIntString("button.edit")); // NOI18N
        m_jEdit.setToolTipText("Edit current Ticket");
        m_jEdit.setFocusPainted(false);
        m_jEdit.setFocusable(false);
        m_jEdit.setMargin(new java.awt.Insets(8, 14, 8, 14));
        m_jEdit.setMaximumSize(new java.awt.Dimension(90, 44));
        m_jEdit.setMinimumSize(new java.awt.Dimension(82, 44));
        m_jEdit.setPreferredSize(new java.awt.Dimension(90, 44));
        m_jEdit.setRequestFocusEnabled(false);
        m_jEdit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                m_jEditActionPerformed(evt);
            }
        });
        m_jButtons.add(m_jEdit);

        m_jRefund.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/openbravo/images/inbox.png"))); // NOI18N
        m_jRefund.setText(AppLocal.getIntString("button.refund")); // NOI18N
        m_jRefund.setToolTipText("Receipt Refund");
        m_jRefund.setFocusPainted(false);
        m_jRefund.setFocusable(false);
        m_jRefund.setMargin(new java.awt.Insets(8, 14, 8, 14));
        m_jRefund.setMaximumSize(new java.awt.Dimension(90, 44));
        m_jRefund.setMinimumSize(new java.awt.Dimension(82, 44));
        m_jRefund.setPreferredSize(new java.awt.Dimension(90, 44));
        m_jRefund.setRequestFocusEnabled(false);
        m_jRefund.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                m_jRefundActionPerformed(evt);
            }
        });
        m_jButtons.add(m_jRefund);

        m_jPrint.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/openbravo/images/printer24.png"))); // NOI18N
        m_jPrint.setText(AppLocal.getIntString("button.print")); // NOI18N
        m_jPrint.setToolTipText("Reprint Receipt");
        m_jPrint.setFocusPainted(false);
        m_jPrint.setFocusable(false);
        m_jPrint.setMargin(new java.awt.Insets(8, 14, 8, 14));
        m_jPrint.setMaximumSize(new java.awt.Dimension(90, 44));
        m_jPrint.setPreferredSize(new java.awt.Dimension(90, 44));
        m_jPrint.setRequestFocusEnabled(false);
        m_jPrint.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                m_jPrintActionPerformed(evt);
            }
        });
        m_jButtons.add(m_jPrint);

        m_jOptions.add(m_jButtons);

        jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
        m_jOptions.add(jPanel2);

        add(m_jOptions, java.awt.BorderLayout.NORTH);

        m_jPanelTicket.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        m_jPanelTicket.setEnabled(false);
        m_jPanelTicket.setLayout(new java.awt.BorderLayout());
        add(m_jPanelTicket, java.awt.BorderLayout.CENTER);

        jPanel3.setLayout(new java.awt.BorderLayout());

        jPanel4.setLayout(new javax.swing.BoxLayout(jPanel4, javax.swing.BoxLayout.Y_AXIS));

        m_jKeys.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                m_jKeysActionPerformed(evt);
            }
        });
        jPanel4.add(m_jKeys);

        jPanel5.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        jPanel5.setLayout(new java.awt.GridBagLayout());

        jButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/openbravo/images/ok.png"))); // NOI18N
        jButton1.setToolTipText("Enter Receipt and touch to Find by Number");
        jButton1.setFocusPainted(false);
        jButton1.setFocusable(false);
        jButton1.setMargin(new java.awt.Insets(8, 14, 8, 14));
        jButton1.setRequestFocusEnabled(false);
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        jPanel5.add(jButton1, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        jPanel5.add(m_jTicketEditor, gridBagConstraints);

        jPanel4.add(jPanel5);

        jPanel3.add(jPanel4, java.awt.BorderLayout.NORTH);

        jPanel1.setLayout(null);

        buttonGroup1.add(jrbSales);
        jrbSales.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
        jrbSales.setText(AppLocal.getIntString("label.sales")); // NOI18N
        jrbSales.setToolTipText("Show Sales Only");
        jrbSales.setFocusPainted(false);
        jrbSales.setFocusable(false);
        jrbSales.setRequestFocusEnabled(false);
        jPanel1.add(jrbSales);
        jrbSales.setBounds(5, 7, 60, 25);

        buttonGroup1.add(jrbRefunds);
        jrbRefunds.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
        jrbRefunds.setForeground(new java.awt.Color(255, 0, 0));
        jrbRefunds.setText(AppLocal.getIntString("label.refunds")); // NOI18N
        jrbRefunds.setToolTipText("Show Refunds Only");
        jrbRefunds.setFocusPainted(false);
        jrbRefunds.setFocusable(false);
        jrbRefunds.setRequestFocusEnabled(false);
        jPanel1.add(jrbRefunds);
        jrbRefunds.setBounds(70, 7, 82, 25);

        jLabel1.setText("Tip:");
        jPanel1.add(jLabel1);
        jLabel1.setBounds(20, 252, 50, 14);

        jButton3.setText("SUBMIT");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });
        jPanel1.add(jButton3);
        jButton3.setBounds(20, 280, 150, 40);
        jPanel1.add(jTipEditor);
        jTipEditor.setBounds(60, 240, 120, 30);

        jeditorTip.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jeditorTipActionPerformed(evt);
            }
        });
        jPanel1.add(jeditorTip);
        jeditorTip.setBounds(0, 30, 194, 200);

        jPanel3.add(jPanel1, java.awt.BorderLayout.CENTER);

        add(jPanel3, java.awt.BorderLayout.EAST);
    }// </editor-fold>//GEN-END:initComponents

    private void m_jEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_jEditActionPerformed

        m_ticketCopy = m_ticket;
        m_TicketsBagTicketBag.showEdit();
        m_panelticketedit.showCatalog();
        m_panelticketedit.setActiveTicket(m_ticket.copyTicket(), null);

    }//GEN-LAST:event_m_jEditActionPerformed

    private void m_jPrintActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_jPrintActionPerformed

        if (m_ticket != null) {
            try {
                ScriptEngine script = ScriptFactory.getScriptEngine(ScriptFactory.VELOCITY);
                script.put("ticket", m_ticket);
                m_TTP2.printTicket(script.eval(m_dlSystem.getResourceAsXML("Printer.TicketPreview")).toString());
            } catch (ScriptException e) {
                JMessageDialog.showMessage(this, new MessageInf(MessageInf.SGN_NOTICE, AppLocal.getIntString("message.cannotprint"), e));
            } catch (TicketPrinterException e) {
                JMessageDialog.showMessage(this, new MessageInf(MessageInf.SGN_NOTICE, AppLocal.getIntString("message.cannotprint"), e));
            }
        }

    }//GEN-LAST:event_m_jPrintActionPerformed

    private void m_jRefundActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_jRefundActionPerformed

        java.util.List aRefundLines = new ArrayList();

        for (int i = 0; i < m_ticket.getLinesCount(); i++) {
            TicketLineInfo newline = new TicketLineInfo(m_ticket.getLine(i));
            aRefundLines.add(newline);
        }

        m_ticketCopy = null;
        m_TicketsBagTicketBag.showRefund();
        m_panelticketedit.showRefundLines(aRefundLines);

        TicketInfo refundticket = new TicketInfo();
        refundticket.setTicketType(TicketInfo.RECEIPT_REFUND);
        refundticket.setCustomer(m_ticket.getCustomer());
        refundticket.setPayments(m_ticket.getPayments());
        m_panelticketedit.setActiveTicket(refundticket, null);

    }//GEN-LAST:event_m_jRefundActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed

        readTicket(-1, jrbSales.isSelected() ? 0 : 1);

    }//GEN-LAST:event_jButton1ActionPerformed

    private void m_jKeysActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_jKeysActionPerformed

        readTicket(-1, jrbSales.isSelected() ? 0 : 1);

    }//GEN-LAST:event_m_jKeysActionPerformed

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
    JTicketsFinder finder = JTicketsFinder.getReceiptFinder(this, m_dlSales, dlCustomers);
    finder.setVisible(true);
    FindTicketsInfo selectedTicket = finder.getSelectedCustomer();
    if (selectedTicket == null) {
        jTipEditor.reset();
        jTipEditor.activate();
        m_jTicketEditor.reset();
        m_jTicketEditor.activate();

    } else {
        readTicket(selectedTicket.getTicketId(), selectedTicket.getTicketType());
    }
}//GEN-LAST:event_jButton2ActionPerformed

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed

        TicketInfo tkt = m_ticket;
        double m_tip = Double.valueOf(jTipEditor.getText());
        String id = tkt.getId();
        List<PaymentInfo> infoList = tkt.getPayments();


        if (!infoList.isEmpty()) {
            PaymentInfo info = infoList.get(0);
            if (info.getIsProcessed()) {
                //Already processed with First Data, do no process same transaction again. 
                JOptionPane.showMessageDialog(this, "This transaction has already been processed.");
                return;
            }
            try {
                m_dlSales.saveTip(m_ticket, m_tip);
            } catch (NullPointerException e) {
            } catch (BasicException b) {
            } finally {

                String AuthNumber = info.getTransactionID();
                if (AuthNumber.equals("no ID")) { // if no ID, it is a cash transactions
                    JOptionPane.showMessageDialog(this, "Not a Credit Sale. Transaction Updated.");
                } else { // Credit sale, proceed with authorization. 
                    NumberFormat formatter = new DecimalFormat("0.00");
                    int reply = JOptionPane.showConfirmDialog(null, "Please Confirm. This step cannot be reversed", "Confirm Amount Adjustment",
                            JOptionPane.YES_NO_OPTION);
                    if (reply == JOptionPane.YES_OPTION) {
                        JOptionPane.showMessageDialog(this, "Authorization in Progress...\n\nTicket Summary"
                                + "\n\nTICKET ID: " + id
                                + "\nTRANSACTION NUMBER: " + info.getTransactionID()
                                + "\nTOTAL: " + formatter.format(Math.abs(info.getTotal()))
                                + "\nTip: " + formatter.format(Math.abs(m_tip)) + ""
                                + "\nNEW TOTAL: " + (info.getTotal() + m_tip));
                        try {


                            AppProperties props = appConfig.getProperties();
                            String sReader = props.getProperty("payment.gateway");

                            String exactID = props.getProperty("payment.commerceid");

                            AltEncrypter cypher = new AltEncrypter("cypherkey" + props.getProperty("payment.commerceid"));
                            String password = cypher.decrypt(props.getProperty("payment.commercepassword").substring(6));

                            boolean m_bTestMode = Boolean.valueOf(props.getProperty("payment.testmode")).booleanValue();
                            boolean bResult = false;
                            String amount = formatter.format(Math.abs(info.getTotal()));
                            amount = URLEncoder.encode(amount.replace(',', '.'), "UTF-8");

                            if ("Global".equals(sReader)) {
                                String HOST = (m_bTestMode)
                                        ? "api.demo.globalgatewaye4.firstdata.com"
                                        : "api.globalgatewaye4.firstdata.com";
                                //amount = Double.toString(Double.valueOf(amount)); // + m_tip);
                                String TotalAmount = Double.toString(Double.valueOf(amount) + m_tip);
                                //Process tip here. 
                                String Blob = info.getReturnMessage();
                                Blob = Blob.replaceFirst("^([\\W]+)<", "<");
                                Blob = Blob.substring(Blob.indexOf("<?xml"));

                                //Parse Blob and get the Transaction_Tag
                                parseSOAP pSoapNew = new parseSOAP();
                                Map getValueNeeded = pSoapNew.getPicklistFromSoapResponse(Blob, "global");
                                String TransTag = (String) getValueNeeded.get("Transaction_Tag");
                                bResult = this.execute(HOST, exactID, password, TotalAmount, TransTag, AuthNumber);

                                //Mercury pay Tip Processing. 
                            } else if ("MercuryPay".equals(sReader)) {
                                String mHOST = (m_bTestMode)
                                        ? "https://w1.mercurydev.net/ws/ws.asmx"
                                        : "https://w1.mercurypay.net/ws/ws.asmx";

                                //Process tip here. 
                                String Blob = info.getReturnMessage();
                                Blob = Blob.replaceFirst("^([\\W]+)<", "<");
                                Blob = Blob.substring(Blob.indexOf("<?xml"));

                                //Parse Blob and get the Transaction_Tag
                                parseSOAP pSoapNew = new parseSOAP();
                                Map getValueNeeded = pSoapNew.getPicklistFromSoapResponse(Blob, "mercury");
                                String AuthorizationCode = (String) getValueNeeded.get("AuthCode");
                                String ReferenceData = (String) getValueNeeded.get("AcqRefData");
                                String RecordNumber = (String) getValueNeeded.get("RecordNo");
                                String finalTip = formatter.format(m_tip);
                                String prepXMLTag = "<?xml version=\"1.0\"?>"
                                        + "<TStream>"
                                        + "<Transaction>"
                                        + "<MerchantID>" + exactID + "</MerchantID>"
                                        + "<TranType>Credit</TranType>"
                                        + "<TranCode>PreAuthCaptureByRecordNo</TranCode>"
                                        + "<InvoiceNo></InvoiceNo>"
                                        + "<RefNo></RefNo>"
                                        + "<Memo>FirstPaymentInt FPIoPOS v2.0.1</Memo>"
                                        + "<PartialAuth>Allow</PartialAuth>"
                                        + "<Frequency>OneTime</Frequency>"
                                        + "<RecordNo>" + RecordNumber + "</RecordNo>"
                                        + "<Amount>"
                                        + "<Purchase>" + amount + "</Purchase>"
                                        + "<Authorize>" + amount + "</Authorize>"
                                        + "<Gratuity>" + finalTip + "</Gratuity>"
                                        + "</Amount>"
                                        + "<TranInfo>"
                                        + "<AuthCode>" + AuthorizationCode + "</AuthCode>"
                                        + "<AcqRefData>" + ReferenceData + "</AcqRefData>"
                                        + "</TranInfo>"
                                        + "</Transaction>"
                                        + "</TStream>";

                                // Following will change for mercury

                                MPSWebRequest comm = new MPSWebRequest();

                                //TODO: Set Web Services password here

                                comm.setWebMethodName("CreditTransaction");
                                comm.setXMLNamespace("http://www.mercurypay.com");
                                comm.setWebServiceURL(mHOST);
                                comm.setParameter("tran", prepXMLTag);
                                comm.setParameter("pw", password);

                                //Capture the response from the web request
                                String responseMercury = comm.sendRequest();

                                parseSOAP pSoapFinal = new parseSOAP();

                                //Collect the XML nodes in from the captured response
                                Map propsMercury = pSoapFinal.getPicklistFromSoapResponse(responseMercury, "mercury");

                                String errorMsg = (String) propsMercury.get("TextResponse");
                                //Check approval status
                                if (pSoapFinal.getResult().equals(LocalRes.getIntString("button.ok"))) {
                                    if ("approved".equals(propsMercury.get("CmdStatus").toString().trim().toLowerCase())) {
                                        //Transaction approved
                                        bResult = true;
                                    } else {
                                        //Transaction declined                    
                                        bResult = false;
                                        JOptionPane.showMessageDialog(this, "Error: " + errorMsg);
                                    }
                                } else {
                                    // Ended up from somewhere else, OK Button wasn't clicked/Decline
                                    bResult = false;
                                }
                            }
                            // Update database record "isProcessed" to true
                            if (bResult) {
                                boolean bIsProcessed = true;

                                m_dlSales.updateTipProcessed(m_ticket, bIsProcessed);
                                // Set the payment as Tip Processed
                                info.setIsProcessed(bIsProcessed);
                                // Show confirmation
                                JOptionPane.showMessageDialog(this, "Transaction successfully processed");
                            }

                        } catch (Exception e) {
                            JOptionPane.showMessageDialog(this, "Error: " + e.getMessage());
                        }
                    }
                }
                jTipEditor.reset();
                jTipEditor.activate();
            }
        }
    }//GEN-LAST:event_jButton3ActionPerformed

    private boolean execute(String _Host, String ExactID, String Password, String Amount, String TranTag, String AuthNum) {
        try {
            SoapRequestBuilder soapRequestBuilder = new SoapRequestBuilder();
            SendAndCommitSource sendAndCommitSource = new SendAndCommitSource(ExactID, Password, Amount, TranTag, AuthNum);
            String result = soapRequestBuilder.sendRequest(sendAndCommitSource, _Host);


            parseSOAP pSoap = new parseSOAP();
            Map props = pSoap.getPicklistFromSoapResponseFinal(result);

            if (pSoap.getResult().equals(LocalRes.getIntString("button.ok"))) {
                if ("00".equals(props.get("EXact_Resp_Code"))) {
                    return true;
                } else {
                    if ("69".equals(props.get("EXact_Resp_Code"))) {
                        JOptionPane.showMessageDialog(this, "Error: " + " Invalid Tip Amount");
                    } else {
                        JOptionPane.showMessageDialog(this, "Error: " + props.get("EXact_Message"));
                    }
                    return false;
                }
            } else {
                JOptionPane.showMessageDialog(this, "Error: " + "An Error Has occured, Please try again");
                return false;
            }
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(this, "Error: " + ex.getMessage());
            return false;
        }

    }

    private class parseSOAP {

        private String result;

        public Map<String, String> getPicklistFromSoapResponse(String soapResponse, String bPayType) throws ServiceException, UnsupportedEncodingException, XMLStreamException {
            soapResponse = soapResponse.replaceFirst("^([\\W]+)<", "<");
            soapResponse = soapResponse.substring(soapResponse.indexOf("<?xml"));


            Map<String, String> values = new LinkedHashMap<String, String>();
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();

            String _Transaction_Tag = null;
            String _CmdStatus = null;
            String _AcqRefData = null;
            String _AuthCode = null;
            String _RecordNo = null;
            String _TextResponse = null;

            InputStream in = new ByteArrayInputStream(soapResponse.getBytes("UTF-8"));
            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
            while (eventReader.hasNext()) {
                XMLEvent event = eventReader.nextEvent();
                if (event.isStartElement()) {
                    if (bPayType == "global") {
                        if (event.asStartElement().getName().getLocalPart().equals("Transaction_Tag")) {
                            event = eventReader.nextEvent();
                            if (event.isCharacters()) {
                                _Transaction_Tag = event.asCharacters().getData();
                            } else {
                                _Transaction_Tag = "";
                            }
                            values.put("Transaction_Tag", _Transaction_Tag);
                            continue;
                        }
                    } else if (bPayType == "mercury") {
                        if (event.asStartElement().getName().getLocalPart().equals("CmdStatus")) {
                            event = eventReader.nextEvent();
                            if (event.isCharacters()) {
                                _CmdStatus = event.asCharacters().getData();
                            } else {
                                _CmdStatus = "";
                            }
                            values.put("CmdStatus", _CmdStatus);
                            continue;
                        }
                        if (event.asStartElement().getName().getLocalPart().equals("AcqRefData")) {
                            event = eventReader.nextEvent();
                            if (event.isCharacters()) {
                                _AcqRefData = event.asCharacters().getData();
                            } else {
                                _AcqRefData = "";
                            }
                            values.put("AcqRefData", _AcqRefData);
                            continue;
                        }
                        if (event.asStartElement().getName().getLocalPart().equals("AuthCode")) {
                            event = eventReader.nextEvent();
                            if (event.isCharacters()) {
                                _AuthCode = event.asCharacters().getData();
                            } else {
                                _AuthCode = "";
                            }
                            values.put("AuthCode", _AuthCode);
                            continue;
                        }
                        if (event.asStartElement().getName().getLocalPart().equals("RecordNo")) {
                            event = eventReader.nextEvent();
                            if (event.isCharacters()) {
                                _RecordNo = event.asCharacters().getData();
                            } else {
                                _RecordNo = "";
                            }
                            values.put("RecordNo", _RecordNo);
                            continue;
                        }
                        if (event.asStartElement().getName().getLocalPart().equals("TextResponse")) {
                            event = eventReader.nextEvent();
                            if (event.isCharacters()) {
                                _TextResponse = event.asCharacters().getData();
                            } else {
                                _TextResponse = "";
                            }
                            values.put("TextResponse", _TextResponse);
                            continue;
                        }


                    }

                }
            }

            result = LocalRes.getIntString("button.ok");
            return values;
        }

        public Map<String, String> getPicklistFromSoapResponseFinal(String soapResponse) throws ServiceException, UnsupportedEncodingException, XMLStreamException {
            soapResponse = soapResponse.replaceFirst("^([\\W]+)<", "<");
            soapResponse = soapResponse.substring(soapResponse.indexOf("<?xml"));
            Map<String, String> values = new LinkedHashMap<String, String>();
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();

            String _EXact_Resp_Code = null;
            String _EXact_Message = null;

            try {
                InputStream in = new ByteArrayInputStream(soapResponse.getBytes("UTF-8"));
                XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
                while (eventReader.hasNext()) {
                    XMLEvent event = eventReader.nextEvent();
                    if (event.isStartElement()) {
                        if (event.asStartElement().getName().getLocalPart().equals("EXact_Resp_Code")) {
                            event = eventReader.nextEvent();
                            _EXact_Resp_Code = event.asCharacters().getData();
                            values.put("EXact_Resp_Code", _EXact_Resp_Code);
                            continue;
                        }
                        if (event.asStartElement().getName().getLocalPart().equals("EXact_Message")) {
                            event = eventReader.nextEvent();
                            _EXact_Message = event.asCharacters().getData();
                            values.put("EXact_Message", _EXact_Message);
                            continue;
                        }
                    }
                }
            } catch (UnsupportedEncodingException e) {
                throw new ServiceException(e);

            } catch (XMLStreamException e) {
                throw new ServiceException(e);
            }
            result = LocalRes.getIntString("button.ok");
            return values;


        }

        public String getResult() {
            return this.result;
        }
    }

    // This class is for First Global Payment Only.
    class SendAndCommitSource {

        Hashtable hMap;

        SendAndCommitSource(String ExactID, String Password, String Amount, String TranTag, String AuthNum) {

            hMap = new Hashtable();

            hMap.put("ExactID", ExactID);
            hMap.put("Password", Password);
            hMap.put("Transaction_Type", "32");
            hMap.put("DollarAmount", Amount);
            hMap.put("Transaction_Tag", TranTag);
            hMap.put("Authorization_Num", AuthNum);

            hMap.put("SurchargeAmount", "");
            hMap.put("Card_Number", "");

            hMap.put("Track1", "");
            hMap.put("Track2", "");
            hMap.put("PAN", "");

            hMap.put("Expiry_Date", "");
            hMap.put("CardHoldersName", "Java Webservice Test");
            hMap.put("VerificationStr1", "");
            hMap.put("VerificationStr2", "");
            hMap.put("CVD_Presence_Ind", "");
            hMap.put("ZipCode", "");
            hMap.put("Tax1Amount", "");
            hMap.put("Tax1Number", "");
            hMap.put("Tax2Amount", "");
            hMap.put("Tax2Number", "");
            hMap.put("Secure_AuthRequired", "");
            hMap.put("Secure_AuthResult", "");
            hMap.put("Ecommerce_Flag", "");
            hMap.put("XID", "");
            hMap.put("CAVV", "");
            hMap.put("CAVV_Algorithm", "");
            hMap.put("Reference_No", "");
            hMap.put("Customer_Ref", "");
            hMap.put("Reference_3", "");
            hMap.put("Language", "en");
            hMap.put("Client_IP", "196.1.1.1");
            hMap.put("Client_Email", "youremail@company.com");
        }
    }
    // This class is for First Global Payment Only. 

    class SoapRequestBuilder {
        // The following section sets the connection requirements.

        String WebServicePath = "/transaction";
        String SoapAction = "http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/SendAndCommit";
        String MethodName = "SendAndCommit";
        String XmlNamespace = "http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/Request";

        public String sendRequest(SendAndCommitSource source, String _Host) {
            String retval = "";

            SSLSocket socket = null;
            try {
                SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
                socket = (SSLSocket) factory.createSocket(_Host, 443);
            } catch (Exception ex1) {
                return ("Error: " + ex1.getMessage());
            }

            try {
                int length = 2330;      // Original xml packet size without the variable data.

                // Sum up all the lengths of field values.
                length += (MethodName.length() * 2) + XmlNamespace.length();
                Enumeration e = source.hMap.elements();
                while (e.hasMoreElements()) {
                    String value = (String) e.nextElement();
                    length += value.length();
                }

                StringBuffer outBuffer = new StringBuffer();
                // post header
                outBuffer.append("POST " + WebServicePath + " HTTP/1.0\r\n");
                outBuffer.append("Host: " + _Host + "\r\n");
                outBuffer.append("Content-Type:text/xml;charset=utf-8\r\n");
                outBuffer.append("Content-Length:" + String.valueOf(length) + "\r\n");
                outBuffer.append("SOAPAction:\"" + SoapAction + "\"" + "\r\n");
                outBuffer.append("\r\n");

                // XML packet to process transactions.
                outBuffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "\n");
                outBuffer.append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:tns=\"http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/\" xmlns:types=\"http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" + "\n");
                outBuffer.append("<soap:Body soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "\n");
                outBuffer.append("<q1:" + MethodName + " xmlns:q1=\"" + XmlNamespace + "\">" + "\n");
                outBuffer.append("<SendAndCommitSource href=\"#id1\" />" + "\n");
                outBuffer.append("</q1:" + MethodName + ">" + "\n");
                outBuffer.append("<types:Transaction id=\"id1\" xsi:type=\"types:Transaction\">" + "\n");

                // Populate the fields in the xml packet.
                e = source.hMap.keys();
                while (e.hasMoreElements()) {
                    String key = (String) e.nextElement();
                    String value = (String) source.hMap.get(key);
                    outBuffer.append("<" + key + " xsi:type=\"xsd:string\">" + value + "</" + key + ">\n");
                }

                outBuffer.append("</types:Transaction>" + "\n");
                outBuffer.append("</soap:Body>" + "\n");
                outBuffer.append("</soap:Envelope>");
                // end of XML packet

                // Print out the packet to stdout for your convenience.
                String sOutBuffer = outBuffer.toString();
                System.out.println(sOutBuffer);

                java.io.OutputStream os = socket.getOutputStream();
                boolean autoflush = true;
                PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush);
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                // send an HTTPS request to the web service
                out.println(sOutBuffer);

                StringBuffer sb = new StringBuffer();     // Result buffer.
                char[] cb = new char[1024];
                int r = 0;
                while ((r = in.read(cb, 0, 1024)) != -1) {
                    sb.append(cb, 0, r);
                }
                // Close read buffer and close socket connnection.
                in.close();
                socket.close();

                // The StringBuffer result now contains the complete result from the
                // webservice in XML format.  You can parse this XML if you want to
                // get more complex results than a single value.

                return sb.toString();
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
                return ex.getMessage();
            }
        }
    }

    private void jeditorTipActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jeditorTipActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_jeditorTipActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup buttonGroup1;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private com.openbravo.editor.JEditorDoublePositive jTipEditor;
    private com.openbravo.editor.JEditorKeys jeditorTip;
    private javax.swing.JRadioButton jrbRefunds;
    private javax.swing.JRadioButton jrbSales;
    private javax.swing.JPanel m_jButtons;
    private javax.swing.JButton m_jEdit;
    private com.openbravo.editor.JEditorKeys m_jKeys;
    private javax.swing.JPanel m_jOptions;
    private javax.swing.JPanel m_jPanelTicket;
    private javax.swing.JButton m_jPrint;
    private javax.swing.JButton m_jRefund;
    private com.openbravo.editor.JEditorIntegerPositive m_jTicketEditor;
    private javax.swing.JLabel m_jTicketId;
    // End of variables declaration//GEN-END:variables
}
